import { Event, IDisposable, URI } from '../../utils';

import type vscode from 'vscode';

// 进程数据事件接口
export interface IProcessDataEvent {
  data: string; // 数据内容
  sync: boolean; // 是否同步
}

// 终端数据缓冲区接口
interface TerminalDataBuffer extends IDisposable {
  data: string[]; // 缓冲数据
  timeoutId: any; // 定时器 id
}

// 终端数据缓冲器，实现数据合并与节流
export class TerminalDataBufferer implements IDisposable {
  private readonly _terminalBufferMap = new Map<string, TerminalDataBuffer>();

  constructor(private readonly _callback: (id: string, data: string) => void) {}

  // 释放所有缓冲区
  dispose() {
    for (const buffer of this._terminalBufferMap.values()) {
      buffer.dispose();
    }
  }

  /**
   * 开始为指定终端 id 缓冲数据
   * @param id 终端 id
   * @param event 数据事件
   * @param throttleBy 节流时间，默认 5ms
   */
  startBuffering(
    id: string,
    event: Event<string | IProcessDataEvent>,
    throttleBy = 5
  ): IDisposable {
    let disposable: IDisposable;
    disposable = event((e: string | IProcessDataEvent) => {
      const data = typeof e === 'string' ? e : e.data;
      let buffer = this._terminalBufferMap.get(id);
      if (buffer) {
        buffer.data.push(data);
        return;
      }

      const timeoutId = setTimeout(() => this._flushBuffer(id), throttleBy);
      buffer = {
        data: [data],
        timeoutId,
        dispose: () => {
          clearTimeout(timeoutId);
          this._flushBuffer(id);
          disposable.dispose();
        },
      };
      this._terminalBufferMap.set(id, buffer);
    });
    return disposable;
  }

  // 停止缓冲指定 id 的数据
  stopBuffering(id: string) {
    const buffer = this._terminalBufferMap.get(id);
    if (buffer) {
      buffer.dispose();
    }
  }

  // 刷新并发送缓冲区数据
  private _flushBuffer(id: string): void {
    const buffer = this._terminalBufferMap.get(id);
    if (buffer) {
      this._terminalBufferMap.delete(id);
      this._callback(id, buffer.data.join(''));
    }
  }
}

// 终端尺寸接口
export interface ITerminalDimensions {
  /**
   * 终端的列数
   */
  readonly cols: number;

  /**
   * 终端的行数
   */
  readonly rows: number;
}

// 终端尺寸重写接口
export interface ITerminalDimensionsOverride extends ITerminalDimensions {
  /**
   * 是否强制 xterm 使用该尺寸，即使超出 UI
   */
  forceExactSize?: boolean;
}

// 终端尺寸 DTO
export interface ITerminalDimensionsDto {
  columns: number;
  rows: number;
}

// 终端链接 DTO
export interface ITerminalLinkDto {
  /** 链接 id，用于激活和释放 */
  id: number;
  /** 链接在行内的起始索引 */
  startIndex: number;
  /** 链接在行内的长度 */
  length: number;
  /** 链接激活时的描述标签 */
  label?: string;
}

// 终端启动错误接口
export interface ITerminalLaunchError {
  message: string;
}

/**
 * 表示原始终端子进程接口，包含 child_process.ChildProcess 的子集
 */
export interface ITerminalChildProcess {
  onProcessData: Event<IProcessDataEvent | string>; // 进程数据事件
  onProcessExit: Event<number | undefined>; // 进程退出事件
  onProcessReady: Event<{ pid: number; cwd: string }>; // 进程就绪事件
  onProcessTitleChanged: Event<string>; // 标题变更事件
  onProcessOverrideDimensions?: Event<ITerminalDimensionsOverride | undefined>; // 尺寸重写事件
  onProcessResolvedShellLaunchConfig?: Event<vscode.TerminalOptions>; // 启动配置解析事件

  /**
   * 启动进程
   * @returns 启动成功返回 undefined，否则返回错误信息
   */
  start(): Promise<ITerminalLaunchError | undefined>;

  /**
   * 关闭终端进程
   * @param immediate 是否立即杀死进程
   */
  shutdown(immediate: boolean): void;

  input(data: string): void; // 输入数据
  resize(cols: number, rows: number): void; // 调整尺寸

  getInitialCwd(): Promise<string>; // 获取初始工作目录
  getCwd(): Promise<string>; // 获取当前工作目录
  getLatency(): Promise<number>; // 获取延迟
}

// 终端进程代理接口（扩展宿主侧）
export interface ITerminalProcessExtHostProxy extends IDisposable {
  /**
   * 该 id 由 clientId 和 shortId 拼接
   */
  readonly terminalId: string;

  emitData(data: string): void; // 发送数据
  emitTitle(title: string): void; // 发送标题
  emitReady(pid: number, cwd: string): void; // 发送就绪事件
  emitExit(exitCode: number | undefined): void; // 发送退出事件
  emitOverrideDimensions(dimensions: ITerminalDimensions | undefined): void; // 发送尺寸重写
  emitInitialCwd(initialCwd: string): void; // 发送初始工作目录
  emitCwd(cwd: string): void; // 发送当前工作目录
  emitLatency(latency: number): void; // 发送延迟

  onInput: Event<string>; // 输入事件
  onResize: Event<{ cols: number; rows: number }>; // 尺寸调整事件
  onShutdown: Event<boolean>; // 关闭事件
  onRequestInitialCwd: Event<void>; // 请求初始工作目录事件
  onRequestCwd: Event<void>; // 请求当前工作目录事件
  onRequestLatency: Event<void>; // 请求延迟事件
}

// 扩展终端启动请求接口
export interface IStartExtensionTerminalRequest {
  proxy: ITerminalProcessExtHostProxy; // 进程代理
  cols: number; // 列数
  rows: number; // 行数
  callback: (error: ITerminalLaunchError | undefined) => void; // 启动回调
}

// 终端 profile 提供者接口
export interface ITerminalProfileProvider {
  createContributedTerminalProfile(
    options: ICreateContributedTerminalProfileOptions
  ): Promise<void>;
}

// 创建终端 profile 的参数
export interface ICreateContributedTerminalProfileOptions {
  icon?: URI | string | { light: URI; dark: URI }; // 图标
  color?: string; // 颜色
  location?:
    | TerminalLocation
    | { viewColumn: number; preserveState?: boolean }
    | { splitActiveTerminal: boolean }; // 位置
}

// 终端位置枚举
export enum TerminalLocation {
  Panel = 1, // 面板
  Editor = 2, // 编辑器
}

// 终端位置字符串枚举
export const enum TerminalLocationString {
  TerminalView = 'view',
  Editor = 'editor',
}

// 终端环境变量接口
export interface ITerminalEnvironment {
  [key: string]: string | null | undefined;
}
